﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace VolunteerHubAdapter
{
    public class VolunteerHubHelper : IDisposable
    {
        private string _authentication;
        private System.Collections.Specialized.NameValueCollection _headers;

        private Models.Settings _settings;
        public VolunteerHubHelper(Models.Settings settings)
        {
            if (settings == null)
                throw new ArgumentNullException("settings", "The settings model is null.");

            _settings = settings;

            _authentication = Convert.ToBase64String(Encoding.UTF8.GetBytes(settings.User + ":" + settings.Password));

            _headers = new System.Collections.Specialized.NameValueCollection(2);
            _headers.Add("Authorization", "Basic " + _authentication);
            _headers.Add("Accept-Encoding", "gzip, deflate");
        }

        private Models.Organization _organization;
        public Models.Organization Organization
        {
            get
            {
                if (_organization == null)
                {
                    System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(_settings.URL + "/api/v1/organization");
                    request.Headers.Add(_headers);

                    using (System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse())
                    {
                        System.IO.Stream receiveStream = new System.IO.Compression.GZipStream(response.GetResponseStream(), System.IO.Compression.CompressionMode.Decompress);
                        System.IO.StreamReader readStream = new System.IO.StreamReader(receiveStream, Encoding.UTF8);

                        _organization = (Models.Organization)Newtonsoft.Json.JsonConvert.DeserializeObject(readStream.ReadToEnd(), typeof(Models.Organization));
                    }

                }

                return _organization;
            }
        }

        private List<Models.Event> _events;
        public List<Models.Event> Events
        {
            get
            {
                if (_events == null)
                {
                    System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(_settings.URL + "/api/v1/events?query=Version&earliestVersion=1");
                    request.Headers.Add(_headers);

                    using (System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse())
                    {
                        System.IO.Stream receiveStream = new System.IO.Compression.GZipStream(response.GetResponseStream(), System.IO.Compression.CompressionMode.Decompress);
                        System.IO.StreamReader readStream = new System.IO.StreamReader(receiveStream, Encoding.UTF8);

                        _events = ((List<Models.Event>)Newtonsoft.Json.JsonConvert.DeserializeObject(readStream.ReadToEnd(), typeof(List<Models.Event>)));
                    }
                }

                return _events;
            }
        }

        public List<Models.Event> GetEvents(int pageId)
        {
            List<Models.Event> events = new List<Models.Event>();

            try
            {
                System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(_settings.URL + "/api/v1/events?query=Version&earliestVersion=1&page=" + pageId);
                request.Headers.Add(_headers);

                using (System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse())
                {
                    System.IO.Stream receiveStream = new System.IO.Compression.GZipStream(response.GetResponseStream(), System.IO.Compression.CompressionMode.Decompress);
                    System.IO.StreamReader readStream = new System.IO.StreamReader(receiveStream, Encoding.UTF8);

                    events = ((List<Models.Event>)Newtonsoft.Json.JsonConvert.DeserializeObject(readStream.ReadToEnd(), typeof(List<Models.Event>)));
                }
            } 
            catch (Exception ex)
            {
                //TODO: Error handling
            }

            return events;
        }

        public List<Models.UserGroup> GetGroups(int pageId)
        {
            List<Models.UserGroup> groups = new List<Models.UserGroup>();

            try
            {
                System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(_settings.URL + "/api/v1/userGroups?page=" + pageId);
                request.Headers.Add(_headers);

                using (System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse())
                {
                    System.IO.Stream receiveStream = new System.IO.Compression.GZipStream(response.GetResponseStream(), System.IO.Compression.CompressionMode.Decompress);
                    System.IO.StreamReader readStream = new System.IO.StreamReader(receiveStream, Encoding.UTF8);

                    groups = ((List<Models.UserGroup>)Newtonsoft.Json.JsonConvert.DeserializeObject(readStream.ReadToEnd(), typeof(List<Models.UserGroup>)));
                }
            }
            catch (Exception ex)
            {
                //TODO: Error handling
            }

            return groups;
        }

        public Models.User GetSpecificUser(Guid id)
        {
            System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(_settings.URL + "/api/v1/users?id=" + id.ToString("B"));

            request.Headers.Add(_headers);

            Models.User user = null;

            using (System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse())
            {
                System.IO.Stream receiveStream = new System.IO.Compression.GZipStream(response.GetResponseStream(), System.IO.Compression.CompressionMode.Decompress);
                System.IO.StreamReader readStream = new System.IO.StreamReader(receiveStream, Encoding.UTF8);

                user = (Models.User)Newtonsoft.Json.JsonConvert.DeserializeObject(readStream.ReadToEnd(), typeof(Models.User), new VolunteerHub.Data.Api.AnswerConverter());
            }

            return user;
        }

        public List<Models.User> GetUsers(int page)
        {
            List<Models.User> result;

            System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(_settings.URL + "/api/v1/users?query=LastUpdate&earliestLastUpdate=" + _settings.LastRunDate.ToString("yyyy-MM-ddThh:mm:ss") + "&page=" + page);
            request.Headers.Add(_headers);

            using (System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse())
            {
                System.IO.Stream receiveStream = new System.IO.Compression.GZipStream(response.GetResponseStream(), System.IO.Compression.CompressionMode.Decompress);
                System.IO.StreamReader readStream = new System.IO.StreamReader(receiveStream, Encoding.UTF8);

                result = ((List<Models.User>)Newtonsoft.Json.JsonConvert.DeserializeObject(readStream.ReadToEnd(), typeof(List<Models.User>), new VolunteerHub.Data.Api.AnswerConverter()));
            }

            return result;
        }

        internal void AddMetaDataForObject(List<OmaticIO.Base.MetaField> metaData, Models.FormQuestion question, Type type)
        {
            foreach (var prop in type.GetProperties())
            {
                if (prop.Name.ToUpper() != "FormQuestionUid".ToUpper())
                    _metaData.Add(new OmaticIO.Base.MetaField() { Name = question.Name + " - " + prop.Name, Type = typeof(string) });
            }
        }

        internal void AddMetaDataForQuestionType(List<OmaticIO.Base.MetaField> metaData, Models.FormQuestion question)
        {
            switch (question.FormQuestionType)
            {
                case VolunteerHub.Data.Api.FormQuestionType.Address:
                    AddMetaDataForObject(metaData, question, typeof(VolunteerHub.Data.Api.FormAnswerAddress));
                    break;

                case VolunteerHub.Data.Api.FormQuestionType.Boolean:
                    AddMetaDataForObject(metaData, question, typeof(VolunteerHub.Data.Api.FormAnswerBoolean));
                    break;

                case VolunteerHub.Data.Api.FormQuestionType.Date:
                    AddMetaDataForObject(metaData, question, typeof(VolunteerHub.Data.Api.FormAnswerDate));
                    break;

                case VolunteerHub.Data.Api.FormQuestionType.Integer:
                    AddMetaDataForObject(metaData, question, typeof(VolunteerHub.Data.Api.FormAnswerInteger));
                    break;

                case VolunteerHub.Data.Api.FormQuestionType.Name:
                    AddMetaDataForObject(metaData, question, typeof(VolunteerHub.Data.Api.FormAnswerName));
                    break;

                default:
                    AddMetaDataForObject(metaData, question, typeof(VolunteerHub.Data.Api.FormAnswerString));
                    break;
            }
        }

        private List<OmaticIO.Base.MetaField> _metaData;
        public List<OmaticIO.Base.MetaField> MetaData
        {
            get
            {
                if (_metaData == null)
                {
                    _metaData = new List<OmaticIO.Base.MetaField>();
                    _metaData.Add(new OmaticIO.Base.MetaField() { Name = "EventID", Type = typeof(string) });
                    _metaData.Add(new OmaticIO.Base.MetaField() { Name = "EventName", Type = typeof(string) });
                    _metaData.Add(new OmaticIO.Base.MetaField() { Name = "EventShortDescription", Type = typeof(string) });
                    _metaData.Add(new OmaticIO.Base.MetaField() { Name = "EventLongDescription", Type = typeof(string) });
                    _metaData.Add(new OmaticIO.Base.MetaField() { Name = "StartTime", Type = typeof(string) });
                    _metaData.Add(new OmaticIO.Base.MetaField() { Name = "EndTime", Type = typeof(string) });
                    _metaData.Add(new OmaticIO.Base.MetaField() { Name = "Location", Type = typeof(string) });
                    _metaData.Add(new OmaticIO.Base.MetaField() { Name = "UserGroupName", Type = typeof(string) });
                    _metaData.Add(new OmaticIO.Base.MetaField() { Name = "UserGroupDescription", Type = typeof(string) });
                    _metaData.Add(new OmaticIO.Base.MetaField() { Name = "UserRegistrationDate", Type = typeof(string) });
                    _metaData.Add(new OmaticIO.Base.MetaField() { Name = "UserRegistrationHours", Type = typeof(string) });
                    _metaData.Add(new OmaticIO.Base.MetaField() { Name = "UserRegistrationDeleted", Type = typeof(string) });
                    _metaData.Add(new OmaticIO.Base.MetaField() { Name = "UserId", Type = typeof(string) });
                    _metaData.Add(new OmaticIO.Base.MetaField() { Name = "Username", Type = typeof(string) });

                    foreach (var question in this.Organization.Forms[0].FormQuestions)
                    {
                        AddMetaDataForQuestionType(_metaData, question);
                    }
                }

                return _metaData;
            }
        }

        public static Type GetAnswerType(string type)
        {
            switch (type)
            {
                case "VolunteerHub.Data.Api.FormAnswerAddress, VolunteerHub.Data.Api":
                    return typeof(VolunteerHub.Data.Api.FormAnswerAddress);
                case "VolunteerHub.Data.Api.FormAnswerBoolean, VolunteerHub.Data.Api":
                    return typeof(VolunteerHub.Data.Api.FormAnswerBoolean);
                case "VolunteerHub.Data.Api.FormAnswerDate, VolunteerHub.Data.Api":
                    return typeof(VolunteerHub.Data.Api.FormAnswerDate);
                case "VolunteerHub.Data.Api.FormAnswerInteger, VolunteerHub.Data.Api":
                    return typeof(VolunteerHub.Data.Api.FormAnswerInteger);
                case "VolunteerHub.Data.Api.FormAnswerName, VolunteerHub.Data.Api":
                    return typeof(VolunteerHub.Data.Api.FormAnswerName);
                case "VolunteerHub.Data.Api.FormAnswerPhotos, VolunteerHub.Data.Api":
                    return typeof(VolunteerHub.Data.Api.FormAnswerPhotos);
                default:
                    return typeof(VolunteerHub.Data.Api.FormAnswerString);
            }
        }

        public Boolean TestConnection()
        {
            Boolean result = false;

            result = ((this.Organization != null) && (this.Organization.Name != string.Empty));
            return result;
        }

        #region IDisposable Members

        public void Dispose()
        {

        }

        #endregion
    }
}
